package org.mikrosopht.client;

import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONException;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.TreeListener;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.Window;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.CloseEvent;


public class TallyWidget extends Composite implements OpenHandler<TreeItem>, CloseHandler<TreeItem> {

  private String movieName;
  private Tree tree = new Tree();
  private TreeItem tallyItem = new TreeItem();
  private TallyWidgetEventReceiver receiver;

  public TallyWidget(String movieName, TallyWidgetEventReceiver receiver) {
    this.movieName = movieName;
    this.receiver = receiver;
    tree.addItem(tallyItem);
    tree.addOpenHandler(this);
    tree.addCloseHandler(this);
    tree.setAnimationEnabled(true);
    initWidget(tree);
  }

  public void update(float tally, int plusVotes, int minusVotes, int screenings) {
    String desc = "" + tally;
    tallyItem.setState(false);
    tallyItem.removeItems();
    if ((minusVotes > 0) || (plusVotes > 0) || (screenings > 0)) {
      desc += " (+" + plusVotes + "/-" + minusVotes;
      if (screenings > 0) {
        desc += "/S=" + screenings;
      }
      desc += ")";
      tallyItem.addItem(new TreeItem());
    }
    tallyItem.setText(desc);
  }

  public void onClose(CloseEvent<TreeItem> event) {
    receiver.onTreeSizeChange();
  }

  public void onOpen(OpenEvent<TreeItem> event) {
    receiver.onTreeSizeChange();
    if (event.getTarget() == tallyItem) {
      String url = URL.encode(MovieVoteConstants.VOTERS_JSON_URL + movieName + "/");
      RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
      try {
        builder.sendRequest(null, new VotersHandler());
      } catch (RequestException e) {
        Window.alert("Couldn't retrieve JSON: " + e);
      }
    }
  }

  private class VotersHandler implements RequestCallback {
    public void onError(Request request, Throwable exception) {
      Window.alert("Couldn't retrieve JSON: " + exception);
    }

    public void onResponseReceived(Request request, Response response) {
      if (response.getStatusCode() == 200) {
        tallyItem.removeItems();
        try {
          JSONObject object = JSONParser.parse(response.getText()).isObject();
          addUserVotesFromJSONArray("Plus Voters", object.get("voters").isArray());
          addUserVotesFromJSONArray("Minus Voters", object.get("downvoters").isArray());
          addScreeningsFromJSONArray("Screenings", object.get("screenings").isArray());
        } catch (JSONException e) {
          MovieVote.redirectToLogin();
        }
        receiver.onTreeSizeChange();
      } else {
        Window.alert("Couldn't retrieve JSON: " + response.getStatusText());
      }
    }

    private void addScreeningsFromJSONArray(String heading, JSONArray array) {
      if (array.size() > 0) {
        TreeItem item = tallyItem.addItem(heading);
        for (int i = 0; i < array.size(); i++) {
          JSONObject voteDetail = array.get(i).isObject();
          TreeItem dateItem = item.addItem(voteDetail.get("date").isString().stringValue());
          JSONArray attendees = voteDetail.get("attendees").isArray();
          for (int j = 0; j < attendees.size(); j++) {
            dateItem.addItem(attendees.get(j).isString().stringValue());
          }
        }
        item.setState(true);
      }
    }

    private void addUserVotesFromJSONArray(String heading, JSONArray array) {
      if (array.size() > 0) {
        TreeItem item = tallyItem.addItem(heading);
        for (int i = 0; i < array.size(); i++) {
          JSONObject voteDetail = array.get(i).isObject();
          item.addItem(voteDetail.get("username").isString().stringValue());
        }
        item.setState(true);
      }
    }
  }
}
